#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <semaphore.h>

sem_t *mutex;
int doAccept(int listenfd)
{
    int connfd;
    
    sem_wait(mutex);
    printf("get in\n");
    connfd= accept(listenfd, NULL, NULL);
    printf("get out\n");
    sem_post(mutex);

    if (connfd <= 0)
        fprintf(stderr, "PID %u %s\n", getpid(),
            strerror(errno));
    else
        printf("PID %u accept\n", getpid());

    return connfd;
}

int main(int argc, char *argv[])
{
    int listenfd, connfd, i;
    struct sockaddr_in servaddr;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(8888);
    bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    listen(listenfd, 5);

    printf("parent is %u\n", getpid());

    mutex = sem_open("sem", O_RDWR|O_CREAT, 0600, 1);
    if (mutex == NULL)
        perror("sem_open error");

    for (i = 0; i < 20; i++) {
        if (fork() == 0) {
            printf("child is %u\n", getpid());
            
            if ((connfd = doAccept(listenfd)) >= 0)
                close(connfd);
            exit(0);
        }
    }

    while (wait(NULL) > 0);
    sem_close(mutex);
    sem_unlink("sem");

    return 0;
}
